package com.nian.common.lock.redis;

import com.nian.redis.cache.JedisClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 用途：
 * 开发：zhangmj
 * 日期：2020/4/13 0013 15:46
 */
@Slf4j
@Service("redisDistributedBaseLock")
public class RedisDistributedBaseLock implements IRedisLock {

    @Autowired
    JedisClient jedisClient;

    /**
     * 获取分布式锁
     * @param lockName 锁名称
     * @param requestId 请求标识
     * @return
     */
    @Override
    public boolean lock(String lockName, String requestId) {
        return lock(lockName, requestId, IRedisLock.TIMEOUT/1000);
    }

    /**
     * 由方法内控制获取锁的尝试间隔时间
     * @param lockName
     * @param requestId
     * @param expireTime
     * @return
     */
    @Override
    public boolean lock(String lockName, String requestId, int expireTime) {
        try {
            Long endTime = System.currentTimeMillis() + IRedisLock.ACQUIRE_TIMEOUT;
            int count = 1;
            while (System.currentTimeMillis() < endTime) {
                Long rs = jedisClient.setNx(lockName, requestId);
                if (rs == 1) {
                    log.info("ThreadName:{} requestId:{} 第 {} 次 获取分布式锁结果:{}", Thread.currentThread().getName(), requestId, count, rs);
                    jedisClient.expire(lockName, expireTime);
                    return true;
                }
                count ++;
                // 尝试获取锁的时间间隔为 10 毫秒
                Thread.currentThread().sleep(10);
            }
        } catch (Exception e) {
            log.error("【Redis】获取分布式式锁失败:", e);
        }
        return false;
    }

    @Override
    public boolean unLock(String lockName, String requestId) {
        try {
            // 释放锁
            String v = jedisClient.get(lockName);
            if(requestId.equals(v)){
                jedisClient.remove(lockName);
                return true;
            }
        } catch (Exception e) {
            log.error("【Redis】释放分布式式锁失败:", e);
        }
        return false;
    }
}
